home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
printer
/
prn2file.arc
/
PRN2FILE.ASM
next >
Wrap
Assembly Source File
|
1987-09-24
|
25KB
|
731 lines
;from VOL6N21.ARC, SEMPER BBS
;----------------------------------------------------------------------
; PRN2FILE.ASM - A resident program which redirects printer output.
; SYNTAX: PRN2FILE d:path:filename.ext [/Pn] [/Bn] [/U]
; 1) Run PRN2FILE with the desired filename to activate it.
; 2) Run it again with no filename to turn off redirection.
; 3) Run it with a differant filename to change destination file.
; 4) Use /P to designate the printer number (defaults to 1)
; 5) Use /B to enter buffer size in K bytes (defaults to 4)
; 6) Use /U to uninstall the program
;----------------------------------------------------------------------
CSEG SEGMENT
ASSUME CS:CSEG,DS:NOTHING
ORG 100H ;Beginning for .COM programs
START: JMP Initialize ;Initialization code is at end
;----------------------------------------------------------------------
; Data area used by this program
;----------------------------------------------------------------------
COPYRIGHT DB "PRN2FILE 1.0 (c) 1987 Ziff Communications Co.$",1AH
PROGRAMMER DB "Tom Kihlken"
REDIRECT_MESS DB "LPT"
PRN_NUM DB "1 Redirected to: $"
BAD_FILENAME DB "Invalid filename.$"
BAD_PARAM DB "Usage: PRN2FILE [path][filename][/Pn][/Bnn][/U]$"
BAD_ALLOC DB "Memory Allocation Error.$"
BAD_UNINSTALL DB "Cannot Uninstall.$"
PRN_TXT DB "PRN$"
CRLF DB 13,10,"$"
ERR_MESSAGE DB 13,10,"*Buffer Overflow*",13,10
MESS_LENGTH EQU $ - OFFSET ERR_MESSAGE
OLDINT08 DD ? ;Old timer tick interrupt vector
OLDINT17 DD ? ;Old printer output vector
OLDINT21 DD ? ;Old dos function interrupt vector
OLDINT28 DD ? ;Old dos waiting interrupt vector
DOS_FLAG DD ? ;Dos busy flag
SWITCH DB 0 ;On/off switch for redirecting printer
TIMEOUT DW 0 ;Holds timeout counter to flush buffer
INSTALLED_SEG DW 0 ;Segment location of installed copy
WRITE_FLAG DB 0 ;Indicates buffer should be written
PRINTER_NUM DW 0 ;Default to first parallel printer
BUFF_POINTER DW 0 ;Pointer to next space in buffer
BUFF_SIZE DW 4 ;Size of buffer
BUFF_SEGMENT DW 0 ;Segment address of buffer
TIME_TO_WRITE EQU 400H ;Flush buffer when this full
;-----------------------------------------------------------------------
; Interrupt 17 routine. (BIOS printer output)
; If output is to the selected printer and switch is on then redirect
; the character into a file.
;-----------------------------------------------------------------------
NewInt17 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
CMP DX,CS:PRINTER_NUM ;Is this the selected printer?
JNE Ignore ;If not, let bios handle it
CMP CS:SWITCH,1 ;Is redirection turned on?
JE Redirect_It ;If on, take jump
Ignore:
JMP CS:OLDINT17 ;Jump to the bios routine
Redirect_It:
STI ;Get interrupts back on
MOV CS:TIMEOUT,91 ;Reset timeout counter
PUSH SI ;Si will be used for a pointer
CMP AH,1 ;Initializing the printer?
JE Write_Buff ;If yes, then flush the buffer
OR AH,AH ;Printing a character?
JNZ Print_Ret ;If not, take jump to return
MOV SI,CS:BUFF_POINTER ;Get pointer to the buffer
CMP SI,CS:BUFF_SIZE ;Is buffer filled up yet?
JE Print_Ret ;If full just return.
PUSH DS ;Save the data segment
MOV DS,CS:BUFF_SEGMENT ;Load DS with the buffer seg
MOV DS:[SI],AL ;Store the character in buffer
POP DS ;Restore data segment
INC SI ;And point to next position
MOV CS:BUFF_POINTER,SI ;Save the new pointer
CMP SI,TIME_TO_WRITE ;Is buffer filling up yet?
JL Print_Ret ;If not, just return
Write_Buff:
MOV CS:WRITE_FLAG,1 ;Signal buffer needs emptying
PUSH DS
PUSH BX
LDS BX,CS:DOS_FLAG ;Get location of dos flag
CMP BYTE PTR [BX],0 ;Is dos busy flag set?
POP BX
POP DS
JNE Print_Ret ;If busy, do nothing
CALL Write_To_File ;This empties the buffer
Print_Ret:
POP SI
MOV AH,10010000B ;Return printer status good
IRET ;Return from interrupt
NewInt17 ENDP
;----------------------------------------------------------------------
; New interrupt 08h (timer tick) decrement the timeout counter. Set
; the flush flag when counter reaches zero.
;----------------------------------------------------------------------
NewInt08 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF ;Simulate an interrupt
CALL CS:OLDINT08 ;Do normal timer routine
DEC CS:TIMEOUT ;Count down the flush time count
JNZ Still_Time ;Count until it gets to zero
CMP CS:BUFF_POINTER,0 ;Anything in buffer?
JE Still_Time ;If not, just continue
MOV CS:WRITE_FLAG,1 ;Set flush trigger
Still_Time:
IRET ;Return from timer interrupt
NewInt08 ENDP
;----------------------------------------------------------------------
; Interrupt 21 routine. (DOS function calls) intercept function 40h
; when it writes to the printer. Also check to see if WRITE_FLAG is
; set to one. If it is then flush the buffer.
;----------------------------------------------------------------------
NewInt21 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF ;Save the callers flags
CMP CS:WRITE_FLAG,1 ;Buffer need to be written?
JNE Dont_Write ;If not, then just return
PUSH DS
PUSH BX
LDS BX,CS:DOS_FLAG ;Get location of DOS flag
CMP BYTE PTR [BX],0 ;Is DOS busy flag set?
POP BX
POP DS
JNE Dont_Write ;If busy, do nothing
CALL Write_To_File ;Empty the buffer now
Dont_Write:
OR AH,AH ;Doing function zero?
JNE Not_Zero
MOV AX,4C00H ;If yes, change it to 4Ch
Not_Zero:
CMP AH,40H ;Writing to a device?
JNE Not_Printer ;If not, just continue
CMP BX,4 ;Writing to the printer handle?
JNE Not_Printer ;If not, just continue
CMP CS:SWITCH,1 ;Is redirection on?
JE Print_It ;If yes, then redirect it
Not_Printer:
POPF ;Recover flags from stack
CLI
JMP CS:OLDINT21 ;Do the DOS function
; Emulate print string function by involking INT 17h
Print_It:
STI ;Reenable interrupts
CLD ;String moves forward
PUSH CX ;Save these registers
PUSH DX
PUSH SI
MOV SI,DX ;Get pointer to string
MOV DX,PRINTER_NUM ;Selected printer ID in DX
JCXZ End_Loop ;Skip loop if count is zero
Print_Loop:
LODSB ;Load next character from string
MOV AH,00 ;Print character function
INT 17H ;BIOS print
LOOP Print_Loop ;Loop through whole string
End_Loop:
POP SI
POP DX
POP CX
MOV AX,CX ;All bytes were output
POPF ;Restore the callers flags
CLC ;Return success status
STI ;Reenable interrupts
RET 2 ;Return with current flags
NewInt21 ENDP
;----------------------------------------------------------------------
; This copies the buffer contents to a file. It should only be called
; when dos is in a reentrant condition. All registers are preserved
;----------------------------------------------------------------------
Write_To_File PROC NEAR
ASSUME DS:NOTHING, ES:NOTHING
PUSH AX ;Save registers we need to use
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH ES
PUSH CS
POP DS ;Set DS to code segment
ASSUME DS:CSEG ;Tell assembler DS is CSEG
MOV WRITE_FLAG,0 ;Clear write request flag
MOV AX,3524H ;Get dos critical error vector
CALL DOS_Function ;Do the dos function
PUSH BX ;Save old vector on stack
PUSH ES
; Replace the dos severe error interrupt with our own routine.
MOV DX,OFFSET NewInt24
MOV AX,2524H ;Setup to change int 24h vector
CALL DOS_Function ;Do the dos function
; First try to open the file. If dos returns with the carry flag set,
; the file didn't exist and we must create it. Once the file is opened,
; advance the file pointer to the end of file to append.
CMP BUFF_POINTER,0 ;Anything in the buffer?
JE Rep_Vector ;If not, no nothing
MOV DX,OFFSET FILENAME ;Point to filename
MOV AX,3D02H ;Dos function to open file
CALL DOS_Function ;Do the dos function
JC File_Not_Found ;Set if file doesn't exist.
MOV BX,AX ;Keep handle in BX also
XOR CX,CX ;Move dos file pointer to the
XOR DX,DX ;End of the file. this lets us
MOV AX,4202H ;Append this to an existing file
CALL DOS_Function ;Do the dos function
JC Close_File ;On any error, take jump
JMP SHORT Write_File
File_Not_Found:
CMP AX,2 ;Was it file not found error?
JNE Rep_Vector ;If not, just quit
MOV CX,0020H ;Attribute for new file
MOV AH,3CH ;Create file for writing
CALL DOS_Function ;Do the dos function
JC Close_File ;On any error, take jump
MOV BX,AX ;Save handle in BX also
Write_File:
xor dx,dx ;MOV DX,0 ;Point to buffer
MOV CX,BUFF_POINTER ;Number of chars in buffer
MOV AH,40H ;Dos write to a device function
PUSH DS
MOV DS,BUFF_SEGMENT ;Point to buffer segment
CALL DOS_Function ;Do the dos function
POP DS
JC Close_File ;On any error, take jump
CMP CX,AX ;Was everything written
JNE Close_File ;If not, it was an error
CMP CX,BUFF_SIZE ;Was buffer full?
JNE Close_File ;If not everything is OK
MOV DX,OFFSET ERR_MESSAGE ;Insert the error message
MOV CX,MESS_LENGTH
MOV AH,40H ;Dos write to file function
CALL DOS_Function ;Do the dos function
Close_File:
MOV AH,3EH ;Dos function to close the file
CALL DOS_Function ;Do the dos function
Rep_Vector:
MOV BUFF_POINTER,0 ;Indicate buffer is empty
POP DS ;Recover int 24h vector from stack
POP DX
MOV AX,2524H ;Restore critical error vector
CALL DOS_Function ;Do the dos function
ASSUME DS:NOTHING
POP ES ;Restore all registers
POP DS
POP DX
POP CX
POP BX
POP AX
RET ;Finished with writing to disk
Write_To_File ENDP
;----------------------------------------------------------------------
; This routine emulates an INT 21 by calling the dos interrupt address
;----------------------------------------------------------------------
DOS_Function PROC NEAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF ;Save the processor flags
CLI ;Clear interrupt enable bit
CALL CS:OLDINT21 ;Execute the interupt procedure
STI ;Enable further interrupts
RET ;And return to calling routine
DOS_Function ENDP
;----------------------------------------------------------------------
; New interrupt 24h (critical dos error). This interrupt is only in
; effect when writing to the disk. It is required to suppress the
; 'Abort, Retry, Ignore' message. All fatal disk errors are ignored.
;----------------------------------------------------------------------
NewInt24 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
STI ;Turn interrupts back on
XOR AL,AL ;Tells dos to ignore the error
MOV CS:SWITCH,AL ;Turn off logging of output
IRET ;And return to dos
NewInt24 ENDP
;----------------------------------------------------------------------
; New interrupt 28h (DOS idle). Check to see if write_flag is set to
; one. If it is, then flush the buffer
;----------------------------------------------------------------------
NewInt28 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
STI
CMP CS:WRITE_FLAG,0 ;Buffer need to be written?
JE Do_Nothing ;If not, just continue
CALL Write_To_File ;Empty the buffer
Do_Nothing:
JMP CS:OLDINT28 ;Continue with old interrupt
NewInt28 ENDP
;----------------------------------------------------------------------
; Here is the code used to initialize prn2file.com. First determine
; if prn2file is already installed. If it is, just copy new parameters
; into the resident programs data area, otherwise save old vectors
; and replace with new ones. The output buffer will later overlay
; this code to conserve memory.
;----------------------------------------------------------------------
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING
Initialize:
MOV DX,OFFSET COPYRIGHT
CALL String_CrLf ;Display the string
; Search for a previously installed copy of prn2file
NOT WORD PTR START ;Modify to avoid false match
XOR BX,BX ;Start search at segment zero
MOV AX,CS ;Compare to this code segment
Next_Segment:
INC BX ;Look at next segment
CMP AX,BX ;Until reaching this code seg
MOV ES,BX
JE Not_Installed
MOV SI,OFFSET START ;Setup to compare strings
MOV DI,SI
MOV CX,16 ;16 bytes must match
REP CMPSB ;Compare DS:SI to ES:DI
OR CX,CX
JNZ Next_Segment ;If no match, try next segment
MOV ES:SWITCH,1 ;Turn redirection on
MOV DX,ES:PRINTER_NUM ;Retrieve old printer number
MOV DS:PRINTER_NUM,DX ;Save it here
MOV AH,1 ;Initialize the resident copy
INT 17H ;To flush it's buffer
ADD DL,31H ;Convert printer num to ascii
MOV PRN_NUM,DL ;Put it into the message area
Not_Installed:
MOV INSTALLED_SEG,ES
PUSH CS
POP ES ;Set ES to this segment
ASSUME ES:CSEG
CMP BYTE PTR DS:[0080],0 ;Anything entered?
JE No_Params ;If not, take jump
Parse:
MOV AL,"/" ;Look for a slash
CALL Load_Params
REPNE SCASB ;Scan for slashes
JCXZ Parse_Done ;Quit when no more slashes
MOV AL,[DI] ;Get the parameter
MOV WORD PTR [DI-1],2020H;Erase the slash and letter
OR AL,32 ;Convert to lower case
CMP AL,"p" ;Is it the "p" parameter
JE Slash_P
CMP AL,"b" ;Is it the "b" parameter
JE Slash_B
CMP AL,"u" ;Is it the "u" parameter
JE Slash_U
Invalid_Param:
MOV DX,OFFSET BAD_PARAM ;Point to error message
JMP Err_Exit
Slash_U:
JMP UnInstall ;Slash "u" means uninstall it
Slash_B:
MOV BUFF_SIZE,0 ;Zero buff size for accumulator
Next_Digit:
MOV AX,BUFF_SIZE ;Get current buff size
MOV BL,10
MUL BL ;Times 10 for next digit
INC DI ;Point to next digit
MOV BL,[DI] ;And get the next one
SUB BL,30H ;Convert it to binary
JC Parse ;If not a digit, keep parsing
CMP BL,9
JA Parse ;If not a digit, keep parsing
MOV BYTE PTR [DI]," ";Erase character from command
XOR BH,BH
ADD AX,BX ;Add in this digit
MOV BUFF_SIZE,AX ;And save the new total
JMP short Next_Digit
Slash_P:
INC DI ;Point to the printer number
MOV AL,[DI]
MOV BYTE PTR [DI]," ";Erase this char from command
MOV PRN_NUM,AL ;Put it in the message area
SUB AL,31H ;Convert it to printer number
XOR AH,AH ;Make it a word
CMP AL,3 ;Printer id must be less than 3
JAE Invalid_Param ;If it isn't, take jump
MOV PRINTER_NUM,AX ;Store the parameter
JMP short Parse ;Look for more parameters
No_Params:
MOV DX,OFFSET REDIRECT_MESS ;Point to message
MOV AH,9 ;Display the string of text
INT 21H ;Using DOS display function
MOV DX,OFFSET PRN_TXT ;Point to "PRN"
CALL String_CrLf ;Display the string
MOV AL,0 ;Turn off redirection switch
JMP Check_For_Install
Parse_Done:
CMP BUFF_SIZE,1 ;Buff must be at least 1K
JB Invalid_Param ;If not, exit with error
CMP BUFF_SIZE,64 ;Check for maximum buff size
JA Invalid_Param ;If above, exit with error
MOV AL," " ;Look for spaces
CALL Load_Params
REPE SCASB ;Scan for non-space character
JCXZ No_Params ;Any letters found?
CMP BYTE PTR [DI],":" ;Was a drive specified?
JNE Get_Def_Drive ;If not, get the default drive
DEC DI ;Now DI points to first letter
MOV AL,[DI] ;Get drive letter in AL
MOV WORD PTR [DI],2020H;Erase the drive and colon
JMP short Store_Drive
Get_Def_Drive:
MOV AH,19H ;Get default drive
INT 21H
ADD AL,65 ;Convert integer drive to ascii
Store_Drive:
MOV AH,":" ;AL has drive, AH has colon
MOV WORD PTR FILENAME,AX ;Store drive and colon
MOV AL,"\" ;Look for a backslash
MOV FILENAME+2,AL ;Add a backslash to filename
CALL Load_Params
REPNE SCASB ;Scan for a backslash
JCXZ Get_Def_Path ;If no path, use current path
MOV DI,OFFSET FILENAME+2 ;Location to store path
JMP short Store_Path
Get_Def_Path:
MOV DL,FILENAME ;Selected drive letter
AND DL,11011111B ;Convert it to upper case
SUB DL,64 ;Convert it to integer
MOV SI,OFFSET FILENAME + 3 ;Put current path at SI
MOV DI,SI ;Save this for search later
MOV AH,47H ;DOS get current directory
INT 21H
JC Bad_Name_Exit ;Exit if invalid drive
MOV AL,0 ;Look for end of path
CMP [DI],AL ;Was there any path?
JE Store_Path ;If not, don't scan it
MOV CX,64 ;Maximum number of bytes in path
REPNE SCASB ;Scan for end of path string
MOV BYTE PTR [DI-1],"\" ;Add the trailing backslash
Store_Path:
PUSH DI ;Save location to append path
MOV AL," " ;Look for blank spaces
CALL Load_Params
REPE SCASB ;Scan for non-blank character
MOV SI,DI
DEC SI ;This is first letter of path
POP DI ;Get back location to append
Copy_Path:
LODSB ;Get next char of path
CMP AL," " ;Is it a blank?
JE Verify_Name ;If yes, its the last char
CMP AL,13 ;Is it a carriage return?
JE Verify_Name ;If yes, its the last char
STOSB ;Store this letter
JMP short Copy_Path ;Copy until end of path found
Verify_Name:
PUSH DI ;Save end of string location
MOV BYTE PTR [DI],"$" ;Mark eos for dos display
MOV DX,OFFSET REDIRECT_MESS ;Point to message
MOV AH,9 ;Display the string of text
INT 21H ;Using dos display function
MOV DX,OFFSET FILENAME ;Point to filename for display
CALL String_CrLf ;Display the string
POP DI
MOV BYTE PTR [DI],0 ;Now make it an ascii string
MOV DX,OFFSET FILENAME ;Dx points to the filename
MOV AX,3D00H ;Open this file for reading
INT 21H
JC Open_Err ;Error may indicate not found
Close_It:
MOV BX,AX ;Get the handle into BX
MOV AH,3EH ;Close the file
INT 21H
JMP short Filename_Ok
Open_Err:
MOV CX,0020H ;Attribute for new file
MOV AH,3CH ;Create file for writing
INT 21H ;Dos function to create file
JNC Close_It ;If no error, just close it
Bad_Name_Exit:
MOV DX,OFFSET BAD_FILENAME
Err_Exit:
CALL String_CrLf ;Display the string
INT 20H ;Just exit to dos
Filename_Ok:
MOV ES,INSTALLED_SEG;Point to installed program
PUSH DS:PRINTER_NUM ;This moves the new printer
POP ES:PRINTER_NUM ;number to the resident copy
MOV DI,OFFSET FILENAME ;Setup to copy the filename
MOV SI,DI
MOV CX,128 ;Copy entire file specification
REP MOVSB ;String move instruction
MOV AL,1 ;Turn redirection on
Check_For_Install:
MOV CX,CS
CMP CX,INSTALLED_SEG
MOV ES,INSTALLED_SEG
MOV ES:SWITCH,AL ;Store the new on/off switch
JE Install ;If not installed yet, do it now
INT 20H ;Otherwise terminate
;----------------------------------------------------------------------
; This subroutine displays a string followed by a CR and LF
;----------------------------------------------------------------------
String_CrLf PROC NEAR
MOV AH,9 ;Display the string of text
INT 21H ;Using dos display function
MOV DX,OFFSET CRLF ;Now point to CR/LF characters
MOV AH,9 ;Send the CR and LF
INT 21H
RET
String_CrLf ENDP
;----------------------------------------------------------------------
; This subroutine sets DI to the command line and CX to the byte count
;----------------------------------------------------------------------
Load_Params PROC NEAR
MOV DI,80H ;Point to parameter area
MOV CL,CS:[DI] ;Get number of chars into CL
XOR CH,CH ;Make it a word
INC DI ;Point to first character
CLD ;String search forward
RET
Load_Params ENDP
;----------------------------------------------------------------------
; This code does the actual installation by storing the existing
; interrupt vectors and replacing them with the new ones.
; Then allocate memory for the buffer. Exit and remain resident.
;----------------------------------------------------------------------
ASSUME DS:CSEG, ES:CSEG
Install:
MOV BX,OFFSET END_OF_CODE ;Get end of resident code
ADD BX,15
MOV CL,4 ;Shift by 4 to divide by 16
SHR BX,CL ;This converts to paragraphs
MOV AH,4AH ;Modify memory block
INT 21H ;Dos setblock function call
JNC Allocate_Buffer ;If it worked ok, then continue
Alloc_Error:
MOV DX,OFFSET BAD_ALLOC ;Err message for bad allocation
JMP Err_Exit ;Display message and exit
Allocate_Buffer:
MOV BX,BUFF_SIZE ;Buffer size in K bytes
MOV CL,6 ;Shift by 6 to get paragraphs
SHL BX,CL ;Buffersize is in paragraphs
MOV AH,48H
INT 21H ;Dos allocate memory
JC Alloc_Error ;If allocation error, take jump
MOV BUFF_SEGMENT,AX ;Save the segment for the buffer
MOV AX,BUFF_SIZE ;Buffer size in K bytes
MOV CL,10 ;Shift by 10 to get bytes
SHL AX,CL
OR AX,AX ;Is buff_size=0 (64K)?
JNZ Size_Ok
DEC AX ;If yes, make it FFFFh
Size_Ok:
MOV BUFF_SIZE,AX ;Now buff_size is in bytes
ASSUME ES:NOTHING
MOV AH,34H ;Get dos busy flag location
INT 21H
MOV WORD PTR [DOS_FLAG] ,BX ;Store flag address
MOV WORD PTR [DOS_FLAG+2],ES
MOV AX,3508H ;Get timer interrupt vector
INT 21H
MOV WORD PTR [OLDINT08] ,BX
MOV WORD PTR [OLDINT08+2],ES
MOV DX, OFFSET NewInt08
MOV AX, 2508H
INT 21H ;Dos function to change vector
MOV AX,3517H ;Get printer interrupt vector
INT 21H
MOV WORD PTR [OLDINT17] ,BX
MOV WORD PTR [OLDINT17+2],ES
MOV DX, OFFSET NewInt17
MOV AX, 2517H
INT 21H ;Dos function to change vector
MOV AX,3521H ;Get dos function vector
INT 21H
MOV WORD PTR [OLDINT21] ,BX
MOV WORD PTR [OLDINT21+2],ES
MOV DX, OFFSET NewInt21
MOV AX, 2521H
INT 21H ;Dos function to change vector
MOV AX,3528H ;Get dos waiting vector
INT 21H
MOV WORD PTR [OLDINT28] ,BX
MOV WORD PTR [OLDINT28+2],ES
MOV DX, OFFSET NewInt28
MOV AX, 2528H
INT 21H ;Dos function to change vector
;----------------------------------------------------------------------
; Deallocate our copy of the enviornment. Exit using interrupt 27h
; (TSR). This leaves code and space for buffer resident.
;----------------------------------------------------------------------
MOV AX,DS:[002CH] ;Get segment of enviornment
MOV ES,AX ;Put it into ES
MOV AH,49H ;Release allocated memory
INT 21H
MOV DX,(OFFSET END_OF_CODE - OFFSET CSEG + 15)SHR 4
MOV AX,3100H
INT 21H ;Terminate and stay resident
;----------------------------------------------------------------------
; This procedure removes PRN2FILE from memory by replacing the vectors
; and releasing the memory used for the code and buffer.
;----------------------------------------------------------------------
ASSUME DS:CSEG, ES:NOTHING
UnInstall:
MOV AL,08H ;Check the timer interrupt
CALL Check_Seg ;If changed, can't uninstall
JNE Cant_UnInstall
MOV AL,17H ;Check the printer interrupt
CALL Check_Seg ;If changed, can't uninstall
JNE Cant_UnInstall
MOV AL,21H ;Check dos interrupt
CALL Check_Seg ;If changed, can't uninstall
JNE Cant_UnInstall
MOV AL,28H ;Check dos idle interrupt
CALL Check_Seg ;If changed, can't uninstall
JNE Cant_UnInstall
MOV ES,INSTALLED_SEG
ASSUME DS:NOTHING, ES:NOTHING
LDS DX,ES:OLDINT08 ;Get original vector
MOV AX,2508H
INT 21H ;Dos function to change vector
LDS DX,ES:OLDINT17 ;Get original vector
MOV AX,2517H
INT 21H ;Dos function to change vector
LDS DX,ES:OLDINT21 ;Get original vector
MOV AX,2521H
INT 21H ;Dos function to change vector
LDS DX,ES:OLDINT28 ;Get original vector
MOV AX,2528H
INT 21H ;Dos function to change vector
MOV ES,ES:BUFF_SEGMENT;Get segment of buffer
MOV AH,49H ;Free its allocated memory
INT 21H
JC Release_Err ;If error, take jump
MOV ES,INSTALLED_SEG;The resident program segment
NOT WORD PTR ES:START
MOV AH,49H ;Free its allocated memory
INT 21H
JC Release_Err ;If error, take jump
MOV AX,4C00H
INT 21H ;Exit to dos
Release_Err:
MOV DX,OFFSET BAD_ALLOC ;Memory allocation error
JMP Err_Exit ;Exit with error message
Cant_UnInstall:
MOV DX,OFFSET BAD_UNINSTALL ;Point to error message
JMP Err_Exit ;Exit with error message
;----------------------------------------------------------------------
; This subroutine checks to see if an interrupt vector points to the
; installed program segment. Returns with ZF=1 if it does.
;----------------------------------------------------------------------
Check_Seg PROC NEAR
MOV AH,35H ;Get the vector
INT 21H ;Dos function to get the vector
MOV AX,ES
CMP AX,INSTALLED_SEG;Is it the installed segment?
RET
Check_Seg ENDP
;----------------------------------------------------------------------
FILENAME LABEL BYTE ;File name will go here
END_OF_CODE = $ + 128 ;Allow 128 bytes for it
CSEG ENDS
END START